package net.zoneland.knowledge.controller;

import com.branchitech.utils.SystemHelper;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import net.zoneland.knowledge.constant.Constants;
import net.zoneland.knowledge.dao.OpLogMapper;
import net.zoneland.knowledge.model.LoginUserPojo;
import net.zoneland.knowledge.model.OpLog;
import net.zoneland.knowledge.model.ResponseResult;
import net.zoneland.knowledge.utils.LoginUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static net.zoneland.knowledge.constant.OplogConstant.*;

/**
 * 访问日志控制层.
 *
 * @author: wangzhiwei
 * @date: 2023/2/3
 */

@RestController
@RequestMapping("/oplog")
public class OpLogController {

    /**
     * 访问日志数据层.
     */
    @Autowired
    private OpLogMapper opLogMapper;

    /**
     * 线程池.
     */
    private ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors(), 0L, TimeUnit.SECONDS, new LinkedBlockingDeque(),
            new ThreadFactoryBuilder().setNameFormat("OpLogController-pool-%d").build());


    /**
     * 访问日志接口.
     *
     * @param request http请求
     * @param opLog   访问日志实体类
     * @return
     */
    @RequestMapping(value = "/log", method = RequestMethod.POST)
    public ResponseResult log(final HttpServletRequest request, @RequestBody final OpLog opLog) {
        final ResponseResult res = new ResponseResult();
        poolExecutor.execute(() -> {
            final String token = request.getHeader(Constants.TOKEN_NAME);
            final LoginUserPojo user = LoginUtils.getCurrentUserByToken(token);
            final String userAgent = getUa(request);
            final String referer = getReferer(request);
            final String ip = getIpAddr(request);
            final String device = String.valueOf(SystemHelper.isMobileDevice(userAgent));
            opLog.setId(UUID.randomUUID().toString());
            opLog.setCreateTime(new Date());
            opLog.setCmpDn(user.getCompanyDN());
            opLog.setCmpName(user.getCompanyName());
            opLog.setUserId(user.getUserID());
            opLog.setUserName(user.getUserName());
            opLog.setToken(token);
            opLog.setUserAgent(userAgent);
            opLog.setReferer(referer);
            opLog.setIp(ip);
            opLog.setAction(referer);
            opLog.setUaDevice(device);
            opLogMapper.insert(opLog);
        });
        return res;
    }


    /**
     * 获取 请求头
     *
     * @param request    http请求
     * @param headerName
     * @return
     */
    private String getHeader(final HttpServletRequest request, final String headerName) {
        if (null == request) {
            return null;
        }
        return request.getHeader(headerName);
    }

    /**
     * 获取请求来源.
     *
     * @param request http请求
     * @return
     */
    private String getReferer(final HttpServletRequest request) {
        return getHeader(request, REFERER);
    }

    /**
     * 获取浏览器信息.
     *
     * @param request http请求
     * @return
     */
    private String getUa(final HttpServletRequest request) {
        return getHeader(request, USER_AGENT);
    }

    /**
     * 查询ip集合.
     */
    private static final List<String> IP_KEYS = Arrays.asList(X_FORWARDED_FOR, PROXY_CLIENT_IP, WL_PROXY_CLIENT_IP);

    /**
     * 获取当前请求者的ip
     *
     * @return {String}
     */
    private String getIpAddr(final HttpServletRequest request) {
        Optional<String> any = IP_KEYS.stream().map(request::getHeader)
                                      .filter(item -> StringUtils.isNotEmpty(item) && !item.equals(UN_KNOW)).findFirst();
        return any.orElseGet(request::getRemoteAddr);
    }



}
